package com.doubao.wechat.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * 微信数据解密工具
 */
@Slf4j
public class WxBizDataCrypt {
    private final String appId;
    private final String sessionKey;
    private final ObjectMapper objectMapper;

    public WxBizDataCrypt(String appId, String sessionKey, ObjectMapper objectMapper) {
        this.appId = appId;
        this.sessionKey = sessionKey;
        this.objectMapper = objectMapper;
    }

    /**
     * 解密数据
     *
     * @param encryptedData 加密数据
     * @param iv            加密算法的初始向量
     * @return 解密后的数据
     */
    public Map<String, Object> decrypt(String encryptedData, String iv) {
        try {
            // Base64解码
            byte[] sessionKeyBytes = Base64.decodeBase64(sessionKey);
            byte[] encryptedDataBytes = Base64.decodeBase64(encryptedData);
            byte[] ivBytes = Base64.decodeBase64(iv);

            // 使用AES-128-CBC进行解密
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

            // 执行解密
            byte[] decrypted = cipher.doFinal(encryptedDataBytes);
            String decryptedString = new String(decrypted, StandardCharsets.UTF_8);

            // 解析JSON
            Map<String, Object> result = objectMapper.readValue(decryptedString, new TypeReference<Map<String, Object>>() {});

            // 校验appId
            @SuppressWarnings("unchecked")
            Map<String, Object> watermark = (Map<String, Object>) result.get("watermark");
            if (watermark == null || !appId.equals(watermark.get("appid"))) {
                log.error("微信数据解密失败，appId不匹配，expected: {}, actual: {}", appId, watermark != null ? watermark.get("appid") : "null");
                return null;
            }

            return result;
        } catch (Exception e) {
            log.error("微信数据解密失败", e);
            return null;
        }
    }
}